package com.zsc.wxm.ysh.anjo.member.service.impl;

import cn.hutool.core.collection.CollUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zsc.wxm.ysh.anjo.member.cache.MemberCacheService;
import com.zsc.wxm.ysh.anjo.member.cache.RoleCacheService;
import com.zsc.wxm.ysh.anjo.member.constant.RoleConstant;
import com.zsc.wxm.ysh.anjo.member.feign.OssService;
import com.zsc.wxm.ysh.anjo.member.feign.ResourcesService;
import com.zsc.wxm.ysh.anjo.member.mapper.MemberMapper;
import com.zsc.wxm.ysh.anjo.member.model.Member;
import com.zsc.wxm.ysh.anjo.member.model.MemberRole;
import com.zsc.wxm.ysh.anjo.member.model.Role;
import com.zsc.wxm.ysh.anjo.member.service.MemberRoleService;
import com.zsc.wxm.ysh.anjo.member.service.MemberService;
import com.zsc.wxm.ysh.anjo.member.service.PermissionService;
import com.zsc.wxm.ysh.anjo.member.service.RoleService;
import com.zsc.wxm.ysh.anjo.result.CodeEnum;
import com.zsc.wxm.ysh.anjo.result.PageResult;
import com.zsc.wxm.ysh.anjo.result.Result;
import com.zsc.wxm.ysh.anjo.service.base.annotations.LoggerHandler;
import com.zsc.wxm.ysh.anjo.service.base.enums.member.MemberStatus;
import com.zsc.wxm.ysh.anjo.service.base.exception.AnjoException;
import com.zsc.wxm.ysh.anjo.service.base.model.member.bo.MemberBO;
import com.zsc.wxm.ysh.anjo.service.base.model.member.dto.AdminRegisterDTO;
import com.zsc.wxm.ysh.anjo.service.base.model.member.dto.MemberInfoDTO;
import com.zsc.wxm.ysh.anjo.service.base.model.member.qo.MemberQuery;
import com.zsc.wxm.ysh.anjo.service.base.model.member.vo.LandlordInfoVO;
import com.zsc.wxm.ysh.anjo.service.base.model.member.vo.MemberRolesVO;
import com.zsc.wxm.ysh.anjo.service.base.model.member.vo.RegisterMemberVO;
import com.zsc.wxm.ysh.anjo.service.base.model.member.vo.UserInfoVO;
import com.zsc.wxm.ysh.anjo.service.base.model.staticdata.UserHouseStaticData;
import com.zsc.wxm.ysh.anjo.service.base.model.staticdata.vo.HouseInfoStaticVO;
import com.zsc.wxm.ysh.anjo.service.base.utils.BeanCopyUtil;
import com.zsc.wxm.ysh.anjo.utils.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.*;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author playmaker
 * @since 2021-01-04
 */
@Service
@Slf4j
public class MemberServiceImpl extends ServiceImpl<MemberMapper, Member> implements MemberService {

    @Resource
    private RedisTemplate<String,String> redisTemplate;

    @Resource
    private RoleService roleService;

    @Resource
    private MemberRoleService memberRoleService;

    @Resource
    private MemberMapper memberMapper;

    @Resource
    private PermissionService permissionService;

    @Resource
    private OssService ossService;

    @Resource
    private ResourcesService resourcesService;

    @Resource
    private MemberCacheService memberCacheService;

    @Resource
    private RoleCacheService roleCacheService;



    /**
     * 判断手机号是否合法，是否已被注册
     *
     * @param phone 手机号
     * @return Member
     */
    private Member phoneIsExist(String phone) {
        //检验手机号是否合法
        if (StringUtils.isEmpty(phone) || !FormUtil.isMobile(phone)) {
            throw new AnjoException(CodeEnum.PHONE_FORMAT_ERROR);
        }
        //手机号码是否被注册
        LambdaQueryWrapper<Member> queryWrapper = Wrappers.lambdaQuery();
        queryWrapper.eq(Member::getPhone, phone).last("limit 1");
        return this.baseMapper.selectOne(queryWrapper);
    }

    /**
     * 设置用户角色
     *
     * @param member   用户
     * @param roleName 角色名称
     */
    private void setMemberRole(Member member,String roleName) {
        //设置角色
        Optional<Role> role = roleCacheService.listByCache()
                .stream()
                .filter(x -> x.getName().equals(roleName))
                .findFirst();
        if (!role.isPresent()) {
            throw new AnjoException("用户角色不存在", 20000);
        }
        Long roleId = role.get().getId();
        MemberRole memberRole = new MemberRole();
        memberRole.setMemberId(member.getId());
        memberRole.setRoleId(roleId);
        memberRoleService.save(memberRole);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void register(RegisterMemberVO registerMemberVo) {
        Assert.notNull(registerMemberVo, "注册参数registerMemberVo不能位空");

        String name = registerMemberVo.getName();
        String phone = registerMemberVo.getPhone();
        String password = Md5Util.md5(registerMemberVo.getPassword());
        //验证码
        String code = registerMemberVo.getCode();

        //检验验证码是否正确
        String checkCode = redisTemplate.opsForValue().get(phone);
        Assert.notNull(checkCode, "验证码不存在或过期");
        Assert.isTrue(code.equals(checkCode), "验证码错误");

        //手机号码是否被注册
        Member member = this.phoneIsExist(phone);
        Assert.isTrue(member != null, CodeEnum.PHOME_IS_EXIT.getMessage());

        member = new Member();
        member.setPhone(phone).setAvatar("").setEmail("")
                .setState(MemberStatus.NORMAL.status)
                .setPassword(password).setUsername(name)
                .setIdentityId("");
        this.save(member);

        //设置用户角色
        setMemberRole(member, RoleConstant.COMMON_USER_ROLE);


    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void registerV2(RegisterMemberVO registerMemberVo) {
        //手机号码是否被注册
        Member member = this.phoneIsExist(registerMemberVo.getPhone());
        log.info("查询的用户信息:{}", member);
        Assert.isTrue(member == null, CodeEnum.PHOME_IS_EXIT.getMessage());
        member = new Member();
        BeanUtils.copyProperties(registerMemberVo, member);
        member.setUsername(registerMemberVo.getName());
        member.setPassword(Md5Util.md5(registerMemberVo.getPassword()));
        this.save(member);
        //设置用户角色
        setMemberRole(member, RoleConstant.COMMON_USER_ROLE);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void adminRegister(AdminRegisterDTO params) {
        Member member = phoneIsExist(params.getPhone());
        Assert.isNull(member, "电话号码已被注册");
        member = new Member();
        member.setPhone(params.getPhone()).setAvatar("").setEmail(params.getEmail())
                .setState(MemberStatus.NORMAL.status)
                .setPassword(Md5Util.md5(params.getPassword()))
                .setUsername(UserUtil.generateUserName())
                .setIdentityId("");
        this.save(member);
        setMemberRole(member, RoleConstant.COMMON_ADMIN_ROLE);

    }

    @Override
    public List<UserInfoVO> getListByQo(MemberQuery query) {
        List<Member> members = memberMapper.listByQo(query);
        List<UserInfoVO> list = new ArrayList<>();
        for (Member member : members) {
            list.add(getUserInfoVO(member));
        }
        return list;
    }

    @LoggerHandler(desc = "登录日志")
    @Override
    public String loginByPhone(String phone, String code) {
        List<Member> list = memberMapper.listByQo(MemberQuery.builder().phone(phone).limit(1L).build());
        Assert.isTrue(CollUtil.isEmpty(list), CodeEnum.PHOME_IS_EXIT.getMessage());
        String checkCode = redisTemplate.opsForValue().get(phone);
        Assert.notNull(checkCode, "验证码不存在或过期");
        Assert.isTrue(code.equals(checkCode), "验证码错误");
        //返回token
        return JwtUtil.getJwtToken(phone);
    }

    @Override
    public void update(MemberInfoDTO params) {
        Member member = memberMapper.selectById(params.getId());
        if (StringUtils.isNotBlank(params.getAvatar())) {
            member.setAvatar(params.getAvatar());
        }
        if (StringUtils.isNotBlank(params.getEmail())) {
            member.setEmail(params.getEmail());
        }
        if (StringUtils.isNotBlank(params.getUsername())) {
            member.setUsername(params.getUsername());
        }
        if (StringUtils.isNotBlank(params.getIdentityId())) {
            member.setIdentityId(params.getIdentityId());
        }
        if (StringUtils.isNotBlank(params.getPhone())) {
            member.setPhone(params.getPhone());
        }
        if (StringUtils.isNotBlank(params.getPassword())) {
            member.setPassword(Md5Util.md5(params.getPassword()));
        }
        if (params.getState() != null) {
            member.setState(params.getState());
        }
        memberMapper.updateById(member);
        //清除对应的缓存
        memberCacheService.removeUserInfoByPhone(member.getPhone());
        memberCacheService.removeByIdCache(member.getId());
    }

    @Override
    public UserInfoVO getUserInfo(HttpServletRequest request) {
        if (StringUtils.isBlank(request.getHeader("Authorization"))) {
            throw new AnjoException(CodeEnum.TOKEN_IS_NOT_EXIT);
        }
        String phone = JwtUtil.getUserPhoneByToken(request.getHeader("Authorization"));
        Member member = memberCacheService.getUserByPhone(phone);
        log.info("查询的用户信息：{}", member.getLandlord());
        return getUserInfoVO(member);
    }

    private UserInfoVO getUserInfoVO(Member member) {
        Map<String, Object> roles = roleService.findRoleByUserId(member.getId());
        //获取已分配的角色
        List<Role> userRoles = (List<Role>) roles.get("assignRoles");
        //获取权限
        List<String> permissions = permissionService.selectPermissionValueByMemberId(member.getId());
        MemberBO memberBo = new MemberBO();
        BeanUtils.copyProperties(member, memberBo);
        UserInfoVO userInfoVo = new UserInfoVO();
        userInfoVo.setMemberBo(memberBo);
        userInfoVo.setRoles(BeanCopyUtil.copyListProperties(userRoles, MemberRolesVO::new));
        userInfoVo.setPermissions(permissions);
        return userInfoVo;
    }

    @Override
    public void updateAvatar(Long id, MultipartFile file) {
        Member member = baseMapper.selectById(id);
        if (StringUtils.isNotBlank(member.getAvatar())) {
            ossService.remove(member.getAvatar());
        }
        Result result = ossService.upload(file);
        log.info("文件上传结果：{}", result);
        if (!result.getSuccess()) {
            throw new AnjoException(result.getMessage(), result.getCode());
        }
        String url = (String) result.getData().get("url");
        member.setAvatar(url);
        baseMapper.updateById(member);
        //清除缓存
        memberCacheService.removeUserInfoByPhone(member.getPhone());
        memberCacheService.removeByIdCache(id);
    }

    @Override
    public MemberBO getOneByQo(MemberQuery query) {
        MemberBO memberBO = new MemberBO();
        if (StringUtils.isNotBlank(query.getPhone())) {
            BeanUtils.copyProperties(memberCacheService.getUserByPhone(query.getPhone()), memberBO);
            return memberBO;
        }
        if (query.getId() != null) {
            BeanUtils.copyProperties(memberCacheService.getUserByIdCache(query.getId()), memberBO);
            return memberBO;
        }
        BeanUtils.copyProperties(baseMapper.listByQo(query).get(0), memberBO);
        return memberBO;
    }

    @Override
    public List<MemberBO> getList(MemberQuery query) {
        List<Member> list = baseMapper.listByQo(query);
        return BeanCopyUtil.copyListProperties(list, MemberBO::new);
    }

    @Override
    public PageResult getLandlordInfos(MemberQuery query) {
        Page<Member> page = new Page<>(query.getCurrPage(), query.getPageSize());
        LambdaQueryWrapper<Member> queryWrapper = Wrappers.lambdaQuery();
        queryWrapper.eq(Member::getLandlord, query.getLandlord());
        if (StringUtils.isNotBlank(query.getName())) {
            queryWrapper.eq(Member::getUsername, query.getName());
        }
        if (StringUtils.isNotBlank(query.getPhone())) {
            queryWrapper.eq(Member::getPhone, query.getPhone());
        }
        page = this.baseMapper.selectPage(page, queryWrapper);
        List<Member> memberList = page.getRecords();
        PageUtil pageUtil = new PageUtil(page);
        if (CollUtil.isEmpty(memberList)) {
            return PageResult.ok(Collections.emptyList(), 0);
        }
        List<LandlordInfoVO> vos = new ArrayList<>();
        for (Member member : memberList) {
            LandlordInfoVO vo = new LandlordInfoVO();
            vo.setId(member.getId());
            vo.setIdentify(vo.getIdentify());
            vo.setCreateTime(member.getCreateTime());
            Result result = resourcesService.getUserHouseByNameAndPhone(member.getUsername(), member.getPhone());
            List<HouseInfoStaticVO> staticVos = JSON.parseArray(JSON.toJSONString(result), HouseInfoStaticVO.class);
            UserHouseStaticData data = new UserHouseStaticData();
            data.setCount(staticVos.size());
            data.setList(staticVos);
            vo.setData(data);
            vos.add(vo);
        }
        return PageResult.ok(vos, pageUtil.getTotal());
    }

    @Override
    public List<MemberBO> getListByIds(List<Long> ids) {
        List<MemberBO> list = new ArrayList<>();
        ids.forEach(id -> {
            MemberBO memberBO = new MemberBO();
            BeanUtils.copyProperties(memberCacheService.getUserByIdCache(id), memberBO);
            list.add(memberBO);
        });
        return list;
    }
}
